package com.seari.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.seari.bean.CYMaxFullLoadBean;
import com.seari.bean.OperateInfoBean;
import com.seari.bean.QuickReportBean;
import com.seari.commonutils.redis.JedisUtilProxy;
import com.seari.commonutils.redis.ex.JedisNotInitializeException;
import com.seari.main.StartupClass;
import com.seari.mapper.OperateMapper;
import com.seari.mapper.TicketingMapper;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;
import redis.clients.jedis.Jedis;

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName OperateServiceImpl
 * @Description TODO
 * @Author LANDSUS
 * @Date 2021/5/14 18:15
 * @Version 1.0
 */
@Service
public class OperateServiceImpl implements OperateService {

    protected static Logger log = LoggerFactory.getLogger(OperateService.class);

    @Autowired
    private WebClient webClient;

    @Autowired
    private PassengerFlowService passengerFlowService;

    @Autowired
    private OperateService operateService;

    @Autowired
    private OperateMapper operateMapper;

    @Autowired
    private TicketingMapper ticketingMapper;

    @Autowired
    private AppCacheService cacheService;

    @Value("${chengYun.host}")
    private String chengYunHost;

    @Value("${chengYun.port}")
    private String chengYunPort;

    private static Map<String,Object> cacheData = new HashMap<>();

    @Override
    public Map<String,Object> operateMessage() {
        Jedis jedis = null;
        List<QuickReportBean> quickReport = new ArrayList<>();

        try {
            jedis = JedisUtilProxy.getJedis();
        } catch (JedisNotInitializeException e) {
            e.printStackTrace();
        }
        StringBuilder stringBuilder = new StringBuilder();

        Map<String,Object> result = new HashMap<>();

        // 查询数据
        List<QuickReportBean> data = operateService.todayQuickReport();
        log.info("xtOperate get successfully");
        if(data.size() > 0){
            // 解析续报
            data.stream().forEach(item -> {
                if(item.getAccidentRemark() != null){
                    String accidentRemark = item.getAccidentRemark();
                    List<Map<String,Object>> parseRemark = new ArrayList<>();
                    Document document = null;
                    try {
                        document = DocumentHelper.parseText(accidentRemark);
                    } catch (DocumentException e) {
                        e.printStackTrace();
                    }
                    List<Element> items = document.getRootElement().elements();
                    items.stream().forEach(item1 -> {
                        Map<String,Object> map = new HashMap<>();
                        List<Element> elements = item1.elements();
                        elements.stream().forEach(element -> map.put(element.getName(),element.getTextTrim()));
                        parseRemark.add(map);
                    });
                    item.setParseRemark(parseRemark);
                }
            });
            // 暂存的速报数据
            Map<String,Object> dataMap = new HashMap<>();
            List<QuickReportBean> showData = new ArrayList<>();
            // 校验数据时效性
            data.stream().forEach(item -> {
                // 如果查询的id不在缓存的数据中，或者id在缓存中但是操作时间大于缓存的，那么就添加到新的缓存数据中
                if(!cacheData.keySet().contains(item.getId()) || item.getOperateTime().compareTo(
                        (Date)cacheData.get(item.getId())
                ) > 0){
                    dataMap.put(item.getId(),item.getOperateTime());
                    showData.add(item);
                }
            });
            // 如果有新的展示数据，则更新缓存中的数据，并将数据存入redis中
            if(dataMap.size() > 0){
                cacheData = dataMap;
                // 将新的数据存入redis，NX：不存在时存入，XX：存在时存入
                jedis.set("quickReport", JSON.toJSONString(showData), "NX", "EX", 60 * 30);
                jedis.set("quickReport", JSON.toJSONString(showData), "XX", "EX", 60 * 30);

                log.info("xtOperate save cache successfully");
                System.out.println(showData);
            }else {
                log.info("xtOperate is not modify");
            }
        }else {
            log.info("xtOperate Does not have today info");
        }


        // 将数据存入缓存，等待查询
        quickReport = JSON.parseArray(jedis.get("quickReport"),QuickReportBean.class);

        // 取出操作时间在当前时间半小时内的运营速报
        if(quickReport != null && quickReport.size() > 0) {
            Date date = new Date();//获取当前时间
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.MINUTE, -30);
            for (QuickReportBean quickReportBean : quickReport) {
                if (quickReportBean.getOperateTime().compareTo(calendar.getTime()) > 0) {
                    stringBuilder.append(quickReportBean.toString());
                }
            }
        }

        // 如果运营速报为空，则取城运日常数据
        if(stringBuilder.length() == 0) {
            Mono<Map> operateInfo =
                    webClient.get().uri("http://{host}:{port}/metrotrans/mapData/getTosMapData",chengYunHost,chengYunPort)
                            .retrieve().bodyToMono(Map.class).doOnError(WebClientResponseException.class, err -> {
                        throw new RuntimeException("getTosMapData error，error Message:"+err.getMessage());
                    });
            // 运营信息
            String memo = ((Map)operateInfo.block().get("data")).get("memo").toString();

            Mono<Map> limitResult =
                    webClient.get().uri("http://{host}:{port}/metrotrans/getLimitCountAndStation",chengYunHost,chengYunPort)
                            .retrieve().bodyToMono(Map.class).doOnError(WebClientResponseException.class, err -> {
                        throw new RuntimeException("getLimitCountAndStation error，error Message:"+err.getMessage());
                    });
            // 限流信息
            Map<String,Object> limitData = (Map)limitResult.block().get("data");
            Integer limitCount = limitData.get("limitCount") == null ? 0 : Integer.valueOf(limitData.get("limitCount").toString());
            String limitStr = limitData.get("limitStr").toString();

            // 安全运营天数
            int safeIndex = memo.indexOf("安全运营");
            String safeString = memo.substring(safeIndex, memo.indexOf("。", safeIndex));
            String safeValue = getInteger(safeString);

            // 各线最大运用车情况
            int planIndex = memo.indexOf("各线图定");
            String planStr = "";
            if(planIndex >= 0){
                planStr = memo.substring(planIndex, memo.lastIndexOf("。",memo.lastIndexOf("。")-1) + 1);
            }else if(memo.indexOf("今日天气") >= 0) {
                planStr = memo.substring(memo.indexOf("今日天气"), memo.indexOf("。", memo.indexOf("今日天气")));
            }

            stringBuilder.append("安全运营天数：").append(safeValue).append("天。限流车站数：")
                    .append(limitCount).append("座。限流信息：").append(limitCount > 0 ? limitStr : "无")
                    .append("。").append(planStr);
        }

        result.put("memo",stringBuilder.toString());
        return result;
    }


    // 获取限流站信息
    public Map<String,Object> getLimitStation(){
        String url = StartupClass.config.getProperty("TosOperateClient_url");
        Map<String,Object> result = new HashMap<>();
        Mono<String> originalString = webClient.get().uri(url).retrieve().bodyToMono(String.class)
                .doOnError(WebClientResponseException.class, err -> {
                    throw new RuntimeException("getLimitStation error，error Message:"+err.getMessage());
        });
        String xmlString = originalString.block().replace("&lt;","<").replace("&gt;",">").replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>","").replace("<string xmlns=\"http://tempuri.org/\">","").replace("</string>","").replace("\r\n","");
//        String xmlString = "<msg><body><serDateTime>2021/05/26 09:01:37</serDateTime><infos><info><runDate>20210526051853</runDate><line>02</line><bs>1733</bs><es>1733</es><cType>1</cType><memo>上海地铁提示信息：出行请错峰，全程戴口罩，限流请配合，进站测体温，人流避拥挤。</memo></info><info><runDate>20210526051853</runDate><line>15</line><bs>1733</bs><es>1733</es><cType>1</cType><memo>上海地铁提示信息：出行请错峰，全程戴口罩，限流请配合，进站测体温，人流避拥挤。</memo></info><info><runDate>20210526074658</runDate><line>02</line><bs>0249</bs><es>0249</es><cType>2</cType><memo /></info><info><runDate>20210526074659</runDate><line>09</line><bs>0942</bs><es>0942</es><cType>2</cType><memo /></info><info><runDate>20210526074700</runDate><line>06</line><bs>0632</bs><es>0632</es><cType>2</cType><memo /></info><info><runDate>20210526074701</runDate><line>04</line><bs>0417</bs><es>0417</es><cType>2</cType><memo /></info><info><runDate>20210526081158</runDate><line>11</line><bs>1147</bs><es>1147</es><cType>2</cType><memo /></info><info><runDate>20210526071212</runDate><line>01</line><bs>0129</bs><es>0128</es><cType>2</cType><memo /></info><info><runDate>20210526071412</runDate><line>01</line><bs>0128</bs><es>0127</es><cType>2</cType><memo /></info><info><runDate>20210526071513</runDate><line>01</line><bs>0130</bs><es>0129</es><cType>2</cType><memo /></info><info><runDate>20210526071513</runDate><line>01</line><bs>0127</bs><es>0126</es><cType>2</cType><memo /></info><info><runDate>20210526073237</runDate><line>16</line><bs>1623</bs><es>1622</es><cType>2</cType><memo /></info><info><runDate>20210526080012</runDate><line>01</line><bs>0131</bs><es>0130</es><cType>2</cType><memo /></info><info><runDate>20210526082343</runDate><line>01</line><bs>0132</bs><es>0131</es><cType>2</cType><memo /></info><info><runDate>20210526084742</runDate><line>11</line><bs>1135</bs><es>1136</es><cType>2</cType><memo /></info></infos></body><vcode /></msg>";
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlString);
        } catch (DocumentException e) {
            return null;
        }
        if(document == null){
            return null;
        }
        Element root = document.getRootElement();
        List<Element> body = root.element("body").elements();
        String date = "";
        List<OperateInfoBean> operateInfoBeanList = new ArrayList<>();
        for (Element element : body) {
            if(element.getName().contains("Date")){
                date = element.getTextTrim();
            }else {
                List<Element> infos = element.elements();
                infos.stream().forEach(info -> {
                    OperateInfoBean operateInfoBean = new OperateInfoBean();
                    Map<String,Object> params = new HashMap<>();
                    info.elements().stream().forEach(param -> params.put(param.getName(),param.getTextTrim()));
                    try {
                        BeanUtils.populate(operateInfoBean,params);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                    operateInfoBeanList.add(operateInfoBean);
                });
            }
        }

        // 将tos信息持久化到本地redis
//        Jedis jedis = JedisUtilProxy.getJedis();
//        jedis.set("operateInfo", JSON.toJSONString(operateInfoBeanList));
//        log.info("tosOperate save cache successfully");

        List<String> limitStationIds = new ArrayList<>();
        List<Map<String,Object>> limitSection = new ArrayList<>();
        List<Map<String,Object>> stationInfo = new ArrayList<>();

        operateInfoBeanList.stream().forEach(item -> {
            if(item.getcType() != 1){
                if(item.getBs().equals(item.getEs())){
                    // 限流车站
                    limitStationIds.add(item.getBs());
                }else{
                    // 限流区段
                    Map<String, Object> objectObjectHashMap = new HashMap<>();
                    objectObjectHashMap.put("beginStationId",item.getBs());
                    objectObjectHashMap.put("endStationId",item.getEs());
                    objectObjectHashMap.put("cType",item.getcType());
                    limitSection.add(objectObjectHashMap);
                }

            }
        });
        if(limitStationIds.size() > 0){
            stationInfo = passengerFlowService.queryStationByStationId(limitStationIds);
        }
        stationInfo.stream().forEach(item -> {
            item.put("stationNameCN",item.get("STATION_NAME_CN"));
            item.put("stationId",Integer.valueOf(item.get("STATION_ID").toString().trim()));
            item.remove("STATION_NAME_CN");
            item.remove("STATION_ID");
        });
        result.put("limitStation",stationInfo);
        result.put("limitStationSize",stationInfo.size());
        result.put("limitSection",limitSection);
        return result;
    }

    @DS("chengyun")
    @Override
    public Integer shangHaiWeather() {
        String weather = ticketingMapper.shangHaiWeather();
        if(StringUtils.isBlank(weather)){
            return 1;
        }
        // 天气优先级，阴>雨>多云=晴
        if(weather.contains("雨")){
            return 2;
        }else if(weather.contains("阴")) {
            return 3;
        }
        return 1;
    }

    /**
     * 查询是否有今天的速报
     * @return
     */
    @DS("xietong")
    @Override
    public List<QuickReportBean> todayQuickReport() {
        return operateMapper.todayQuickReport();
    }
    /**
     * "annualFlow": "2900.44",    // 年累计客流量（亿
     *         *         "trulyFlow": "1234",        // 当日实时客流（万
     *         *         "onlineTrainNum": "100",    // 实时在线车辆数（辆
     *         *         "trulyAvgFullLoad": "50"    // 实时平均满载率（百分比
     */
    @Override
    public Map<String,Object> scaleSummarize() {
        Map<String,Object> result = new HashMap<>();
        // annualFlow trulyFlow onlineTrainNum trulyAvgFullLoad
        int i = Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
        BigDecimal totalFlow = new BigDecimal("29.44");
        BigDecimal multiply = totalFlow.divide(new BigDecimal("365"), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(i)).setScale(2);
        Map<String,Object> totalDate = (Map<String,Object>)cacheService.getCacheObject("totalDate");
        String dayNetPassengerflow = totalDate.get("dayNetPassengerflow").toString();
        List<CYMaxFullLoadBean> fullloadList = (List<CYMaxFullLoadBean>)cacheService.getCacheObject("fullloadList");
        BigDecimal totalAvg = new BigDecimal("0");
        if(fullloadList!= null && fullloadList.size() > 0){
            for (CYMaxFullLoadBean cyMaxFullLoadBean : fullloadList) {
                if(cyMaxFullLoadBean != null && cyMaxFullLoadBean.getAvgSaturation() != null){
                    totalAvg = totalAvg.add(new BigDecimal(cyMaxFullLoadBean.getAvgSaturation().toString()));
                }
            }
            BigDecimal trulyAvgFullLoad = totalAvg.divide(new BigDecimal(fullloadList.size()), 2, RoundingMode.HALF_UP);
            result.put("trulyAvgFullLoad",trulyAvgFullLoad.toString());
        }else {
            result.put("trulyAvgFullLoad","0.15");
        }
        result.put("onlineTrainNum",totalDate.get("todayTrainNum"));
        result.put("annualFlow",multiply.toString());
        result.put("trulyFlow",new BigDecimal(dayNetPassengerflow).divide(new BigDecimal("10000"),2,RoundingMode.HALF_UP).toString());
        return result;
    }

    private String getInteger(String safeString) {
        Pattern compile = Pattern.compile("\\d+");
        Matcher matcher = compile.matcher(safeString);
        while(matcher.find()) {
            return matcher.group();
        }
        return "";
    }

}
